package com.fingersoft.stomp;


import android.os.Handler;
import android.os.Message;
import android.text.TextUtils;
import android.util.Log;

import androidx.annotation.Nullable;

import com.fingersoft.business.BusinessContext;
import com.fingersoft.business.calendar.ICalendarProvider;
import com.fingersoft.im.api.UserAgent;
import com.fingersoft.im.event.EventManager;
import com.fingersoft.im.utils.AppUtils;
import com.google.gson.GsonBuilder;

import org.greenrobot.eventbus.EventBus;
import org.json.JSONException;
import org.json.JSONObject;

import java.util.ArrayList;
import java.util.List;

import cn.fingersoft.util.BuildConfigUtil;
import io.reactivex.CompletableTransformer;
import io.reactivex.android.schedulers.AndroidSchedulers;
import io.reactivex.schedulers.Schedulers;
import ua.naiksoftware.stomp.Stomp;
import ua.naiksoftware.stomp.StompHeader;
import ua.naiksoftware.stomp.client.StompClient;
import ua.naiksoftware.stomp.client.StompCommand;
import ua.naiksoftware.stomp.client.StompMessage;

/**
 * Created by mahuan on 2018/2/23.
 */

public class MyStompClient {

    @Nullable
    public static StompClient mStompClient;
    private static String TAG = "StompClient";
    private static String url = "";
    private static final int CODE_OK = 200;
    private static final int CODE_FAIL = 403;
    private static final String TYPE_SOCKET_OPENPOPOVER = "openPopover";
    private static final String TYPE_SOCKET_ALERT = "alert";
    private static final String TYPE_SOCKET_ONLINETYPE = "onLineType";
    private static final String TYPE_SOCKET_REFRESHDATA = "refreshData";
    private static HeartBeatRunnable mHeartBeatRunnable;
    private static final long RATE_HEARTBEAT = 1000 * 30;
    private static Handler mHandler;
    private static final String PLATFORM = "aPhone";

    /**
     * 创建client 实例
     *
     * @param mHandler
     */
    public static void createStompClient(Handler mHandler) {
        if (null != mStompClient) {
            return;
        }
        url = AppUtils.BASE_API_URL + "socket";
        String[] s = url.split(":");
        String socketurl = "ws";
        if (url.startsWith("http")) {
            socketurl = "ws";
        }
        if (url.startsWith("https")) {
            socketurl = "wss";
        }
        for (int i = 1; i < s.length; i++) {
            socketurl = socketurl + ":" + s[i];
        }
        mStompClient = Stomp.over(Stomp.ConnectionProvider.OKHTTP, socketurl);
        List<StompHeader> headers = new ArrayList<>();
        GsonBuilder gb = new GsonBuilder();
        gb.disableHtmlEscaping();
        String info = gb.create().toJson(new UserAgent(PLATFORM, AppUtils.getTokenInfo().getUserToken(), AppUtils.getTokenInfo().getDid()));
        StompHeader sh4 = new StompHeader("Emp-Info", info);
        headers.add(sh4);
        mStompClient.connect(headers);
        mStompClient.lifecycle().subscribeOn(Schedulers.io())
            .observeOn(AndroidSchedulers.mainThread())
            .subscribe(lifecycleEvent -> {
                switch (lifecycleEvent.getType()) {
                    case OPENED:
                        Log.d(TAG, "Stomp connection opened");
                        registerStompTopic(mHandler);
                        break;
                    case ERROR:
                        Log.e(TAG, "Stomp Error", lifecycleEvent.getException());
                        break;
                    case CLOSED:
                        Log.d(TAG, "Stomp connection closed");
                        break;
                    default:
                }
            });
    }

    /**
     * 断开websocket链接
     */
    public static void disconnect() {
        if (null != mStompClient) {
            try {
                mStompClient.disconnect();
                mStompClient = null;
            } catch (Exception e) {
                e.printStackTrace();
            }
        }
        if (null != mHandler) {
            mHandler.removeCallbacks(mHeartBeatRunnable);
        }
    }

    /**
     * 接收消息
     *
     * @param handler
     */
    public static void registerStompTopic(Handler handler) {
        mHandler = handler;
        if (mStompClient == null) {
            return;
        }
        mStompClient.topic("/user/" + AppUtils.J_ECODE + "/user/notice")
            .subscribeOn(Schedulers.io())
            .observeOn(AndroidSchedulers.mainThread())
            .subscribe((topicMessage) ->
                Log.e(TAG, "all: " + topicMessage.getPayload())
            );

        String uId = AppUtils.getTokenInfo().getUid();
        mStompClient.topic("/user/" + uId + "@" + PLATFORM + "/user/notice")
            .subscribeOn(Schedulers.io())
            .observeOn(AndroidSchedulers.mainThread())
            .subscribe((topicMessage) ->
                parseTopicMessage(topicMessage)
            );

        mStompClient.topic("/user/" + uId + "/user/notice")
            .subscribeOn(Schedulers.io())
            .observeOn(AndroidSchedulers.mainThread())
            .subscribe(topicMessage -> {
                parseTopicMessage(topicMessage);
            });

        mStompClient.topic("/user/" + AppUtils.getTokenInfo().getDid() + "/user/notice")
            .subscribeOn(Schedulers.io())
            .observeOn(AndroidSchedulers.mainThread())
            .subscribe(topicMessage -> {
                parseTopicMessage(topicMessage);
            });

        if (null == mHeartBeatRunnable) {
            mHeartBeatRunnable = new HeartBeatRunnable();
        }
        if (null != mHandler) {
            mHandler.removeCallbacks(mHeartBeatRunnable);
            mHandler.postDelayed(mHeartBeatRunnable, RATE_HEARTBEAT);
        }
    }

    private static void parseTopicMessage(StompMessage topicMessage) {
        Log.e(TAG, "private: " + topicMessage.getPayload());
        try {
            JSONObject jb = new JSONObject(topicMessage.getPayload());
            if (null == jb) {
                return;
            }
            int code = jb.getInt("code");
            String msg = jb.getString("msg");
            if (code == CODE_FAIL) {
                // rong启用下默认使用rong的多端在线控制
                if (!BuildConfigUtil.INSTANCE.getBoolean("useRong")) {
                    Message message = new Message();
                    message.what = 0;
                    message.obj = msg;
                    mHandler.sendMessage(message);
                }
            }
            if (code == CODE_OK) {
                if (!jb.isNull("data")) {
                    JSONObject data = jb.getJSONObject("data");
                    if (data.has("type")) {
                        String type = data.getString("type");
                        String userId = data.getJSONObject("body").getString("userId");
                        String typeNum = data.getJSONObject("body").getString("type");
                        if (type.equals(TYPE_SOCKET_OPENPOPOVER)) {

                        } else if (type.equals(TYPE_SOCKET_ALERT)) {
                            Message message = new Message();
                            message.what = 1;
                            message.obj = data.getString("body");
                            mHandler.sendMessage(message);
                        } else if (type.equals(TYPE_SOCKET_ONLINETYPE)) {
                            EventBus.getDefault().post(new EventManager.OnlineStatus(userId, typeNum));
                        } else if (type.equals(TYPE_SOCKET_REFRESHDATA)) {
                            try {
                                String bodyType = data.getJSONObject("body").getString("type");
                                if (!TextUtils.isEmpty(bodyType)) {
                                    if (bodyType.equals("calendar")) {
                                        ICalendarProvider iCalendarProvider = BusinessContext.Companion.getCalendarEvent();
                                        if (null != iCalendarProvider) {
                                            BusinessContext.Companion.getCalendarEvent().queryNewEvents();
                                        }
                                    }else if(bodyType.equals("apiBadge")){
                                        EventBus.getDefault().post(new EventManager.OnApiBadge());
                                    }
                                } else {
                                    //unsupported type
                                }
                            } catch (JSONException e) {
                                e.printStackTrace();
                            }
                        } else {
                            //unsupported type
                        }
                    }
                }
            }
        } catch (JSONException e) {
            e.printStackTrace();
        }
    }

    /**
     * 发送消息
     *
     * @param data
     */
    public static void send(String data) {
        if (mStompClient == null) {
            return;
        }
        String deviceId = AppUtils.getTokenInfo().getDid();
        String usertoken = AppUtils.getTokenInfo().getUserToken();
        List<StompHeader> headers = new ArrayList<>();
        GsonBuilder gb = new GsonBuilder();
        gb.disableHtmlEscaping();
        String info = gb.create().toJson(new UserAgent(PLATFORM, usertoken, deviceId));
        StompHeader sh4 = new StompHeader("Emp-Info", info);
        headers.add(sh4);
        headers.add(new StompHeader(StompHeader.DESTINATION, "/emp-ws/user"));
        mStompClient.send(new StompMessage(StompCommand.SEND, headers, data))
            .compose(applySchedulers())
            .subscribe(() -> {
                Log.d(TAG, "Send  Completed");
            }, throwable -> {
                Log.d(TAG, "Send  Error");
            });
    }

    protected static CompletableTransformer applySchedulers() {
        return upstream -> upstream
            .unsubscribeOn(Schedulers.newThread())
            .subscribeOn(Schedulers.io())
            .observeOn(AndroidSchedulers.mainThread());
    }

    private static class HeartBeatRunnable implements Runnable {

        @Override
        public void run() {
            if (null != mStompClient && mStompClient.isConnected()) {
                if (null != mHandler && null != mHeartBeatRunnable) {
                    mHandler.postDelayed(mHeartBeatRunnable, RATE_HEARTBEAT);
                }
                mStompClient.send("\"type\": \"heatBeat\"");
            }
        }
    }
}
